package org.dromara.quickswing.ui.app;

import cn.hutool.core.text.CharSequenceUtil;
import org.dromara.quickswing.QSApplication;
import org.dromara.quickswing.constant.QSConstant;
import org.dromara.quickswing.database.QSDbManager;
import org.dromara.quickswing.database.QSDbManagerFactory;
import org.dromara.quickswing.events.QSEventBus;
import org.dromara.quickswing.utils.QSArgsUtils;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;

/**
 * @author Jin
 */
public abstract class QSContext<T extends QSApplication, P extends QSPrefs> {

    private static final QSEventBus qsEventBus = new QSEventBus();

    private QSDbManager QSDbManager;

    protected abstract T createApplication(String[] args, P preferences);

    protected abstract P loadPreferences(String[] args);

    protected abstract String getAppDataPath();

    protected abstract String getAppResourceBundlePath();

    public T createApplication(String[] args) {
        P preferences = loadPreferences(args);
        this.initializeProperty(args, preferences);
        this.initializeDatabaseManager(preferences);
        this.performBeforeInitialization(preferences);
        T application = createApplication(args, preferences);
        this.performPostInitialization(application, preferences);
        return application;
    }

    private void initializeProperty(String[] args, P preferences) {
        String appDataPath = QSArgsUtils.getArgValue(args, QSConstant.KEY_APP_DATA_PATH);
        if (appDataPath != null) {
            preferences.setDataPath(appDataPath);
        } else {
            preferences.setDataPath(getAppDataPath());
        }
        String appName = QSArgsUtils.getArgValue(args, QSConstant.KEY_APP_NAME);
        if (appName != null) {
            preferences.setAppName(appName);
        }
        String appLanguage = QSArgsUtils.getArgValue(args, QSConstant.KEY_APP_LANGUAGE);
        if (appLanguage != null) {
            preferences.setLanguage(appLanguage);
        }
        String appTheme = QSArgsUtils.getArgValue(args, QSConstant.KEY_APP_THEME);
        if (appTheme != null) {
            preferences.setAppTheme(appTheme);
        }
        String appResourceBundlePath = QSArgsUtils.getArgValue(args, QSConstant.KEY_APP_RESOURCE_BUNDLE_PATH);
        if (appResourceBundlePath != null) {
            preferences.setResourceBundlePath(appResourceBundlePath);
        } else {
            String resourceBundlePath = getAppResourceBundlePath();
            if (CharSequenceUtil.isNotEmpty(resourceBundlePath)) {
                preferences.setResourceBundlePath(resourceBundlePath);
            }

        }
    }

    private void initializeDatabaseManager(P preferences) {
        QSDbManager = QSDbManagerFactory.getInstance().getDatabaseManager(preferences);
    }

    protected void populatePreferencesFromApplication(T app, P preferences) {
        preferences.setLocation(app.getLocation());
        preferences.setSize(app.getSize());
        preferences.setLanguage(app.getLanguage());
        preferences.setAppTheme(app.getTheme());
    }
    protected void performBeforeInitialization(P preferences) {
    }

    protected void performPostInitialization(T application, P preferences) {
    }

    public QSEventBus getEventBus() {
        return qsEventBus;
    }

    public QSDbManager getDatabaseManager() {
        return QSDbManager;
    }

    public abstract <D, R> Future<R> taskSubmit(Callable<D> callable, BiFunction<D, Exception, R> function);

    public abstract <D> void taskExecute(Callable<D> callable, BiConsumer<D, Exception> consumer);

}
